import hashlib
import json
import logging
import urllib
from datetime import datetime
import re
from urllib.parse import urlencode

import jsonpath
import requests
from apscheduler.schedulers.background import BackgroundScheduler
from django_apscheduler.models import DjangoJob
from django.http import JsonResponse
from django_apscheduler.jobstores import DjangoJobStore
from lapi_app.models.environment_model.environment import Environment
from lapi_app.models.task_case.task import Task, Task_result
from lapi_app.models.testcase_model.testcase import Variable_local, Asserts, Testcase
from lapi_app.models.testcase_model.testcase_tree import Menu

logger = logging.getLogger('django')
scheduler = BackgroundScheduler()
scheduler.add_jobstore(DjangoJobStore(), 'default')
bodys = {}
# 钉钉推送
HEADERS = {"Content-Type": "application/json"}


def add_task(request):
    path = request.get_full_path()
    data = json.loads(request.body)
    logger.info("path = " + path)
    bodys.update(data)
    tasks = data["task_cases"]
    # 新增任务
    if path == "/api/task/add_task":
        if data["task_name"] == '' or data["run_type"] == '':
            return JsonResponse({
                "code": 100,
                "message": "必要参数不可以为空"
            })
        elif data["task_type"] == 1:
            if data["task_time"] is None:
                return JsonResponse({
                    "code": 100,
                    "message": "任务周期不可以为空"
                })
        elif data["task_type"] == 2:
            if data["task_hour"] == "":
                return JsonResponse({
                    "code": 100,
                    "message": "任务周期不可以为空"
                })
        elif data["task_type"] == 3:
            if data["task_week_days"] == "" or data["task_week_times"] == "":
                return JsonResponse({
                    "code": 100,
                    "message": "任务周期不可以为空"
                })
        elif Task.objects.filter(task_name=data["task_name"]).exists():
            return JsonResponse({
                "code": 100,
                "message": "任务名称已存在"
            })
        for case in tasks:
            if "id" not in case.keys() or "step" not in case.keys():
                return JsonResponse({
                    "code": 100,
                    "message": "接口或执行顺序不可以为空"
                })
            elif "id" in case.keys() or "step" in case.keys():
                if case["id"] is None or case["step"] == '':
                    return JsonResponse({
                        "code": 100,
                        "message": "接口或执行顺序不可以为空"
                    })
        for i in range(len(tasks)):
            for j in range(len(tasks) - i - 1):
                if tasks[j]["id"] == tasks[j + 1]["id"]:
                    return JsonResponse({
                        "code": 100,
                        "message": "不能出现同一个接口"
                    })
                if tasks[j]["step"] == tasks[j + 1]["step"]:
                    return JsonResponse({
                        "code": 100,
                        "message": "不能出现同一个执行顺序"
                    })
        try:
            task = Task.objects.create(task_name=data["task_name"], task_case=data["task_cases"],
                                       task_type=data["task_type"], ding_talk=data["ding_talk"],
                                       task_time=data["task_time"],
                                       run_type=data["run_type"],
                                       user_id=data["user_id"],
                                       task_hour=data["task_hour"],
                                       task_description=data["task_description"],
                                       task_week_times=data["task_week_times"],
                                       task_week_days=data["task_week_days"],
                                       task_status=data["task_status"])
            if data["task_status"] == 1:
                Task.objects.filter(id=task.id).update(active=2)
                if data["task_type"] == 1:
                    # 某个时刻执行
                    bodys.update({"task_id": task.id})
                    scheduler.add_job(run_task, 'date', id=str(task.id),
                                      run_date=data["task_time"], args=(bodys,))
                    # register_events(scheduler)
                    scheduler.start()
                elif data["task_type"] == 2:
                    # 间隔时间性执行
                    bodys.update({"task_id": task.id})
                    scheduler.add_job(run_task, 'interval', id=str(task.id), minutes=data["task_hour"],
                                      interval_offset='10s', args=(bodys,))
                    # register_events(scheduler)
                    scheduler.start()
                elif data["task_type"] == 3:
                    # 每周几点执行
                    start_time = data["task_week_times"].split(':')
                    h = int(start_time[0])
                    m = int(start_time[1])
                    bodys.update({"task_id": task.id})
                    scheduler.add_job(run_task, 'cron', id=str(task.id),
                                      day_of_week=data["task_week_days"], hour=h, minute=m, interval_offset='10s', args=(bodys,))
                    # register_events(scheduler)
                    scheduler.start()

                return JsonResponse({
                    "code": 200,
                    "message": "任务创建成功，任务启动",
                    "data": data
                })
            else:
                return JsonResponse({
                    "code": 200,
                    "message": "任务创建成功，任务未启动",
                    "data": data
                })
        except Exception as e:
            return JsonResponse({
                "code": 100,
                "message": str(e),
            })
    # 编辑任务
    elif path == "/api/task/edit_task":
        if data["task_name"] == '' or data["run_type"] == '':
            return JsonResponse({
                "code": 100,
                "message": "必要参数不可以为空"
            })
        elif data["task_type"] == 1:
            if data["task_time"] is None:
                return JsonResponse({
                    "code": 100,
                    "message": "任务周期不可以为空"
                })
        elif data["task_type"] == 2:
            if data["task_hour"] == "":
                return JsonResponse({
                    "code": 100,
                    "message": "任务周期不可以为空"
                })
        elif data["task_type"] == 3:
            if data["task_week_days"] == "" or data["task_week_times"] == "":
                return JsonResponse({
                    "code": 100,
                    "message": "任务周期不可以为空"
                })
        task_names = Task.objects.exclude(id=data["task_id"])
        for t in task_names:
            if t.task_name == data["task_name"]:
                return JsonResponse({
                    "code": 100,
                    "message": "任务名称已存在"
                })
        for case in tasks:
            if "id" in case.keys() or "step" in case.keys():
                if case["id"] is None or case["step"] == '':
                    return JsonResponse({
                        "code": 100,
                        "message": "接口或执行顺序不可以为空"
                    })
            elif "id" not in case.keys() or "step" not in case.keys():
                return JsonResponse({
                    "code": 100,
                    "message": "接口或执行顺序不可以为空"
                })
        for i in range(len(tasks)):
            for j in range(len(tasks) - i - 1):
                if tasks[j]["id"] == tasks[j + 1]["id"]:
                    return JsonResponse({
                        "code": 100,
                        "message": "不能出现同一个接口"
                    })
                if tasks[j]["step"] == tasks[j + 1]["step"]:
                    return JsonResponse({
                        "code": 100,
                        "message": "不能出现同一个执行顺序"
                    })
        else:
            try:
                Task.objects.filter(id=data["task_id"]). \
                    update(task_name=data["task_name"], task_case=data["task_cases"],
                           task_type=data["task_type"], task_week_times=data["task_week_times"],
                           task_week_days=data["task_week_days"], user_id=data["user_id"],
                           task_hour=data["task_hour"],
                           run_type=data["run_type"],
                           task_time=data["task_time"], ding_talk=data["ding_talk"],
                           task_description=data["task_description"], task_status=data["task_status"],
                           update_time=datetime.now().strftime("%Y-%m-%d %H:%M:%S"))
                if data["task_status"] == 1:
                    Task.objects.filter(id=data["task_id"]).update(active=2)
                    if DjangoJob.objects.filter(id=str(data["task_id"])).count() > 0:
                        # 如果存在相同的ID任务，先删掉1
                        tasks = DjangoJob.objects.filter(id=str(data["task_id"]))
                        tasks.delete()
                        logger.info("原定时任务删除成功")
                    if data["task_type"] == 1:
                        bodys.update({"task_id": data["task_id"]})
                        # 某个时刻执行
                        scheduler.add_job(run_task, 'date', id=str(data["task_id"]),
                                          run_date=data["task_time"], args=(bodys,))
                        # register_events(scheduler)
                        scheduler.start()
                    elif data["task_type"] == 2:
                        # 间隔时间性执行
                        bodys.update({"task_id": data["task_id"]})
                        scheduler.add_job(run_task, 'interval', id=str(data["task_id"]), minutes=data["task_hour"], args=(bodys,))
                        # register_events(scheduler)
                        scheduler.start()
                    elif data["task_type"] == 3:
                        # 每周几点执行
                        bodys.update({"task_id": data["task_id"]})
                        start_time = data["task_week_times"].split(':')
                        h = int(start_time[0])
                        m = int(start_time[1])
                        scheduler.add_job(run_task, 'cron', id=str(data["task_id"]),
                                          day_of_week=data["task_week_days"], hour=h, minute=m, args=(bodys,))
                        # register_events(scheduler)
                        scheduler.start()
                    return JsonResponse({
                        "code": 200,
                        "message": "编辑任务成功，任务已启动",
                        "edit_time": datetime.now().strftime("%Y-%m-%d %H:%M:%S")
                    })
                else:
                    if DjangoJob.objects.filter(id=str(data["task_id"])).count() >= 1:
                        # 如果存在相同的ID任务，先删掉
                        DjangoJob.objects.filter(id=str(data["task_id"])).delete()
                    return JsonResponse({
                        "code": 200,
                        "message": "编辑任务成功，任务未启动",
                        "edit_time": datetime.now().strftime("%Y-%m-%d %H:%M:%S")
                    })
            except Exception as e:
                return JsonResponse({
                    "code": 100,
                    "message": "编辑任务失败",
                    "Exception": str(e)
                })


def run_task(data):
    tasks = bodys["task_cases"]
    task_id = bodys["task_id"]
    if Task_result.objects.filter(task_id=task_id).exists():
        result = Task_result.objects.filter(task_id=task_id)
        result.delete()
    else:
        pass
    for i in range(len(tasks)):
        for j in range(len(tasks) - i - 1):
            if tasks[j]["step"] > tasks[j + 1]["step"]:
                tasks[j], tasks[j + 1] = tasks[j + 1], tasks[j]
    task_list = []
    for menu_id in tasks:
        cs = Menu.objects.filter(id=menu_id["id"])
        for c in cs:
            case_id = c.testcase_id
            task_list.append(case_id)
    for task in task_list:
        task_status = int
        assert_task_status = int
        variable_task_status = int
        cases = Testcase.objects.filter(id=task)
        for case in cases:
            env = Environment.objects.get(id=case.t_environment_id)
            url = case.t_url
            req_url = env.e_address + url

            # url处理
            if "${" in req_url and "}" in req_url:
                key = re.findall(r"\${(.+?)}", req_url)
                for a in range(len(key)):
                    v_key = "${" + key[a] + "}"
                    value_variable = Variable_local.objects.filter(local_name=str(v_key))
                    if value_variable.count() > 0:
                        variable = value_variable[0].local_result
                        req_url = req_url.replace(v_key, variable)
                    else:
                        task_status = 0
                        return JsonResponse({
                            "code": 101,
                            "message": str(v_key) + "变量数据库未找到"
                        })
            logger.info("请求url=" + req_url)

            # headers处理
            if case.t_header == '':
                headers = eval(case.t_header)
            else:
                try:
                    head = str(case.t_header)
                    if "${" in head and "}" in head:
                        key = re.findall(r"\${(.+?)}", head)
                        for b in range(len(key)):
                            h_key = "${" + key[b] + "}"
                            value_variable = Variable_local.objects.filter(local_name=str(h_key))
                            if value_variable.count() > 0:
                                variable = value_variable[0].local_result
                                head = head.replace(h_key, variable)
                            else:
                                task_status = 0
                                return JsonResponse({
                                    "code": 101,
                                    "message": str(h_key) + "变量数据库未找到"
                                })
                    headers = eval(head)
                except Exception as e:
                    task_status = 0
                    return JsonResponse({
                        "code": 101,
                        "message": "header参数类型错误",
                        "system_log": e
                    })
            logger.info("请求头=" + str(headers))

            # body处理
            if case.t_body == '' or case.t_body == {}:
                payload = eval(case.t_body)
            else:
                try:
                    body = str(case.t_body)
                    if "${" in body and "}" in body:
                        key = re.findall(r"\${(.+?)}", body)
                        for b in range(len(key)):
                            b_key = "${" + key[b] + "}"
                            value_variable = Variable_local.objects.filter(local_name=str(b_key))
                            if value_variable.count() > 0:
                                variable = value_variable[0].local_result
                                body = body.replace(b_key, variable)
                            else:
                                task_status = 0
                                return JsonResponse({
                                    "code": 101,
                                    "message": str(b_key) + "变量数据库未找到"
                                })
                    payload = eval(body)
                except Exception as e:
                    task_status = 0
                    return JsonResponse({
                        "code": 101,
                        "message": "body参数类型错误",
                        "system_log": e
                    })
            logger.info("请求体=" + str(payload))

            if case.api_type == 1:
                # 普通接口
                pass

            # 请求方法：1：get， 2：post， 3：put， 4：delete
            # 参数类型：1:form-data， 2:Json， 3:x-www-form-urlencoded， 4:None
            # method处理
            # params处理
            p = case.t_params
            params = {}
            if not p:
                for item in p:
                    if item['key'] == '' or item['value'] == '':
                        params = {}
                    else:
                        params[item['key']] = item['value']
            else:
                params = {}
            logger.info("请求参数=" + str(params))
            method = str(case.t_method)
            logger.info("请求方法 =" + method)
            body_type = str(case.t_type)
            logger.info("参数类型 =" + body_type)

            res = None
            # Get
            if method == "1":
                if body_type == "1":
                    res = requests.get(req_url, params=payload, headers=headers)
                    logger.info("响应结果 =" + res.text)
                if body_type == "2":
                    res = requests.get(req_url, json=payload, headers=headers)
                    logger.info("响应结果 =" + res.text)
                if body_type == "3":
                    res = requests.get(req_url, data=payload, headers=headers)
                    logger.info("响应结果 =" + res.text)
                if body_type == "4":
                    res = requests.get(req_url, params=params, headers=headers)
                    logger.info("响应结果 =" + res.text)

            # Post
            if method == "2":
                if body_type == "1":
                    res = requests.post(req_url, data=payload, headers=headers)
                    logger.info("响应结果 =" + res.text)
                if body_type == "2":
                    res = requests.post(req_url, json=payload, headers=headers)
                    logger.info("响应结果 =" + res.text)
                if body_type == "3":
                    res = requests.post(req_url, data=payload, headers=headers)
                    logger.info("响应结果 =" + res.text)
                if body_type == "4":
                    res = requests.post(req_url, data=payload, headers=headers)
                    logger.info("响应结果 =" + res.text)
            # Put
            if method == "3":
                if body_type == "1":
                    res = requests.put(req_url, data=payload, headers=headers)
                    logger.info("响应结果 =" + res.text)
                if body_type == "2":
                    res = requests.put(req_url, json=payload, headers=headers)
                    logger.info("响应结果 =" + res.text)
                if body_type == "3":
                    res = requests.put(req_url, data=payload, headers=headers)
                    logger.info("响应结果 =" + res.text)
                if body_type == "4":
                    res = requests.post(req_url, data=payload, headers=headers)
                    logger.info("响应结果 =" + res.text)

            # Delete
            if method == "4":
                if body_type == "1":
                    res = requests.delete(req_url, data=payload, headers=headers)
                    logger.info("响应结果 =" + res.text)
                if body_type == "2":
                    res = requests.delete(req_url, json=payload, headers=headers)
                    logger.info("响应结果 =" + res.text)
                if body_type == "3":
                    res = requests.delete(req_url, data=payload, headers=headers)
                    logger.info("响应结果 =" + res.text)
                if body_type == "4":
                    res = requests.delete(req_url, data=payload, headers=headers)
                    logger.info("响应结果 =" + res.text)

            if res is None or res == "":
                assert_res = res.text
            else:
                assert_res = json.loads(res.text)
                # assert处理
                assert_result = []
                result = []
                assert_dict = {}
                a_data = Asserts.objects.filter(assert_testcase_id=case.id)
                if a_data is not None:
                    for a in a_data:
                        assert_dict.update({
                            a.assert_key: a.assert_value
                        })
                else:
                    assert_status = {
                        "status": "无参数断言"
                    }
                    result.append(assert_status)
                if assert_dict:
                    for key, value in assert_dict.items():
                        if str(value) == str(jsonpath.jsonpath(res.json(), key)[0]):
                            assert_status = {
                                "status": True,
                                "assert_key": key,
                                "assert_value": str(value),
                            }
                        else:
                            assert_task_status = 0
                            assert_status = {
                                "status": False,
                                "assert_key": key,
                                "assert_value": str(value),
                            }
                        result.append(assert_status)
                assert_result.extend(result)
                logger.info(f"断言结果={result}")

                # variable提取处理
                extract_result = []
                extract = case.t_extract
                if not extract:
                    extract_result = []
                else:
                    for v in extract:
                        if v["variable_name"] == '' or v["variable_name"] == '':
                            extract_dict = {
                                "message": "无参数提取"
                            }
                            extract_result.append(extract_dict)
                        elif Variable_local.objects.filter(local_name=v["variable_name"]).count() >= 0:
                            # 提取变量
                            try:
                                res_result = json.loads(res.text)
                            except Exception as e:
                                logger.info(str(e))
                            v_data = v["variable_data"].split(".")
                            logger.info("提取内容 =" + str(v_data))
                            try:
                                for a in v_data:
                                    if "[" in a and "]" in a:
                                        variable_1 = a.split('[')[0]
                                        variable_2 = a.split('[')[1].split(']')[0]
                                        res_result = res_result[variable_1][variable_2]
                                    else:
                                        res_result = res_result[a]
                                extract_dict = {
                                    "variable_name": v["variable_name"],
                                    "variable_data": v["variable_data"],
                                    "variable_result": str(res_result),
                                    "message": "参数提取成功"
                                }
                                extract_result.append(extract_dict)
                            except Exception as e:
                                variable_task_status = 0
                                extract_dict = {
                                    "variable_name": v["variable_name"],
                                    "variable_data": v["variable_data"],
                                    "variable_result": "参数提取失败" + str(e)
                                }
                                extract_result.append(extract_dict)
                    for e in extract_result:
                        if Variable_local.objects.filter(local_name=e["variable_name"]).count() > 0:
                            Variable_local.objects.filter(local_name=e["variable_name"]). \
                                update(local_data=e["variable_data"], local_result=e["variable_result"])
                        elif Variable_local.objects.filter(local_name=e["variable_name"]).count() == 0:
                            Variable_local.objects.filter(local_name=e["variable_name"]). \
                                create(local_name=e["variable_name"], local_data=e["variable_data"],
                                       local_result=e["variable_result"],
                                       local_user_id=bodys["user_id"])
                    logger.info("参数提取结果 =" + str(extract_result))
                    logger.info("接口响应时间 =" + str(res.elapsed.total_seconds()) + 's')
        if variable_task_status == 0 or assert_task_status == 0 or task_status == 0:
            Task_result.objects.create(task_status=0, task_result=json.loads(res.text),
                                       task_runtime=datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
                                       task_assert=assert_result, task_extract=extract_result,
                                       case_id=case.id, task_id=task_id,
                                       task_res_time=str(res.elapsed.total_seconds()) + 's')
        else:
            Task_result.objects.create(task_status=1, task_result=json.loads(res.text),
                                       task_runtime=datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
                                       task_assert=assert_result, task_extract=extract_result,
                                       case_id=case.id, task_id=task_id,
                                       task_res_time=str(res.elapsed.total_seconds()) + 's')

    send_ding = Task.objects.filter(id=task_id)
    send_ding.update(active=3)
    for ding in send_ding:
        if ding.ding_talk == "":
            pass
        else:
            if Task_result.objects.filter(task_id=task_id, task_status=0).count() > 0:
                data_info = {
                    "msgtype": "text",
                    "text": {
                        "content": "定时任务ID:（任务名称：" + ding.task_name + "：id = " + str(task_id) + '）LAPI测试报告-info：定时任务执行失败，详情请去LAPI平台查看：http://172.16.60.38:9528/login'
                    },
                    "isAtAll": False
                }
            else:
                data_info = {
                    "msgtype": "text",
                    "text": {
                        "content": "定时任务ID:（任务名称：" + ding.task_name + "：id = " + str(task_id) + '）LAPI测试报告-info：定时任务执行成功，请去查看：http://172.16.60.38:9528/login'
                    },
                    "isAtAll": False
                }
            requests.post(ding.ding_talk, data=json.dumps(data_info), headers=HEADERS)
